🌴 Sync 2026-10-12 12:02:15

This commit is contained in:
github-actions[bot] committed 2026-10-12 12:02:15 +08:00
1 parent 1b64546588
commit 887e5ac8e3
261 files changed
+52646 -35012

No files matched your search

@@ -11,7 +11,7 @@
# Check if the user gave an argument
if [ -z "$1" ]; then
echo "Usage: $0 {getmac|lanip|getnetstat|bestcrypto|ovpnver|ovpnstart|ovpnrestart|ovpnstop|ovpnservice|firewallservice|firewallnft|openssldgst|symlink|readstatus|iroute|cleanipdns|checkip|resolveip|checkport|checksroute|checkddns|publicip|wgetddns|ddnsservice|ucisortovpn|cleanup|keymeta|keygenclean|initkeys|keygen} [parameters]"
echo "Usage: $0 {getmac|lanip|getnetstat|bestcrypto|securepath|readfile|writefile|makedir|removefile|removedir|statfile|ovpnver|ovpnstart|ovpnrestart|ovpnstop|ovpnservice|firewallexecute|firewallservice|firewallnft|openssldgst|symlink|readstatus|iroute|cleanipdns|checkip|resolveip|checkport|checksroute|checkddns|publicip|wgetddns|ddnsservice|ucisortovpn|cleanup|keymeta|keygenclean|initkeys|keygen} [parameters]"
exit 1
fi
@@ -91,18 +91,222 @@ bestcrypto() {
return 0
}
# Central security gate to format and validate paths
securepath() {
shift # Remove "securepath" from the arguments list
local target_path="$1"
local allow_write="$2" # Optional: "write" to block read-only folders
# 1. Critical Guard: Block empty inputs or directory traversal hacks (..)
if [ -z "$target_path" ] || echo "$target_path" | grep -q '\.\.'; then
return 1
fi
# 2. Fix: If the path does not start with a slash, add it dynamically
case "$target_path" in
/*) ;;
*) target_path="/$target_path" ;;
esac
# 3. Check if the absolute path is inside the allowed sandbox folders
case "$target_path" in
/proc/uptime)
# Strictly read-only /proc/uptime
[ "$allow_write" = "write" ] && return 1
echo "$target_path"
return 0
;;
/proc/*)
# Strictly read-only PID checks!
# Validate that the path contains ONLY digits after /proc/ (e.g., /proc/1234)
[ "$allow_write" = "write" ] && return 1
if echo "$target_path" | grep -q -E '^/proc/[0-9]+$'; then
echo "$target_path"
return 0
fi
return 1
;;
/var/run/openvpn.keygen.lock|/var/run/fw4.state|/var/run/openvpn.*.status)
# Read-only files! Block if write access is requested.
[ "$allow_write" = "write" ] && return 1
echo "$target_path"
return 0
;;
/tmp/openvpn.keygen*|/tmp/run/openvpn.*.status)
# Read-only files! Block if write access is requested.
[ "$allow_write" = "write" ] && return 1
echo "$target_path"
return 0
;;
/etc/config/openvpn|/etc/config/openvpn-def)
# Isolated Config Files: Full read and write access for configuration
echo "$target_path"
return 0
;;
/etc/openvpn/luci/*|/etc/openvpn/keys/*)
# Isolated App Storage: Full read and write access for certificates and profiles
echo "$target_path"
return 0
;;
*)
# Any other file, system folder, or unlisted path is strictly blocked
return 1
;;
esac
}
# Securely read file from disk
readfile() {
shift # Remove "readfile" from the arguments list
# Get the validated absolute path from securepath
local filepath=$(securepath "securepath" "$1" "read")
if [ -z "$filepath" ]; then
echo "ERROR: Access denied." >&2
return 1
fi
if [ -e "$filepath" ]; then
cat "$filepath"
return 0
else
echo "problem: $filepath" >&2
fi
return 1
}
# Securely write to disk with root-only access (0600)
writefile() {
shift # Remove "writefile" from the arguments list
# Get the validated absolute path from securepath with write permission check
local filepath=$(securepath "securepath" "$1" "write")
local content="$2"
if [ -z "$filepath" ]; then
echo "ERROR: Access denied. Protected path." >&2
return 1
fi
# Ensure the target folder exists before writing files into it
mkdir -p "$(dirname "$filepath")"
# Write the contents cleanly into the target destination path
echo -n "$content" > "$filepath"
# Restrict permissions immediately so only root can access it
chmod 600 "$filepath"
return 0
}
# Securely create directory paths with correct system permissions (0700)
makedir() {
shift # Remove "makedir" from the arguments list
# Get the validated absolute path from securepath with write permission check
local dirpath=$(securepath "securepath" "$1" "write")
if [ -z "$dirpath" ]; then
echo "ERROR: Access denied. Protected path." >&2
return 1
fi
# Create the folder layout securely (chmod 700 is root-only access)
mkdir -p "$dirpath"
chmod 700 "$dirpath"
return 0
}
# Securely remove files from disk
removefile() {
shift # Remove "removefile" from the arguments list
# Get the validated absolute path from securepath with write permission check
local filepath=$(securepath "securepath" "$1" "write")
if [ -z "$filepath" ]; then
echo "ERROR: Access denied. Protected path." >&2
return 1
fi
# Delete the file safely without generating errors if it does not exist
rm -f "$filepath"
return 0
}
# Securely remove full directories from disk
removedir() {
shift # Remove "removedir" from the arguments list
# Get the validated absolute path from securepath with write permission check
local dirpath=$(securepath "securepath" "$1" "write")
if [ -z "$dirpath" ] || [ "$dirpath" = "/" ]; then
echo "ERROR: Access denied or core root wipe blocked." >&2
return 1
fi
# Delete the directory and all its contents safely
rm -rf "$dirpath"
return 0
}
# Securely get file statistics
statfile() {
shift # Remove "statfile" from the arguments list
# Get the validated absolute path from securepath
local filepath=$(securepath "securepath" "$1" "read")
if [ -z "$filepath" ]; then
return 1
fi
# Check if something exists at the path (file, directory or symlink)
if [ -e "$filepath" ] || [ -L "$filepath" ]; then
local file_type="file"
local file_size=0
[ -d "$filepath" ] && file_type="directory"
[ -L "$filepath" ] && file_type="symlink"
if [ "$file_type" = "file" ]; then
# wc -c returns "123 /path/to/file", we use awk to extract just the number
file_size=$(wc -c "$filepath" 2>/dev/null | awk '{print $1}')
[ -z "$file_size" ] && file_size=0
fi
# Get modification time
local mtime=$(date -r "$filepath" +%s 2>/dev/null || echo 0)
# Print simulated JSON string
echo "{\"type\":\"$file_type\",\"size\":$file_size,\"mtime\":$mtime}"
return 0
fi
return 1
}
# OpenVPN version
ovpnver() {
openvpn --version
return 0;
}
# Central validator for sleep seconds parameter
validatesleep() {
local sec="$1"
# Check if empty, contains non-digits, is less than 1, or greater than 60
if [ -z "$sec" ] || ! echo "$sec" | grep -q '^[0-9]\+$' || [ "$sec" -lt 1 ] || [ "$sec" -gt 60 ]; then
return 1
fi
return 0
}
# OpenVPN self healing start engine
ovpnstart() {
shift # Remove "ovpnstart" from the arguments list
local inst="$1"
local sleepsec="$2"
# Execute optional validated sleep delay before doing any work
if validatesleep "$sleepsec"; then
sleep "$sleepsec"
fi
# If $inst contains only spaces or is empty, ensure it is completely empty
if [ -z "$(echo "$inst" | tr -d ' ')" ]; then
inst=""
fi
@@ -120,22 +324,18 @@ ovpnstart() {
local check_inst="${line##*.}"
check_inst="${check_inst%%=*}"
# Only check profiles that are enabled by the user
if [ "$(uci -q get openvpn."${check_inst}".enabled)" = "1" ]; then
# If an enabled instance process is not running, trigger the repair
if ! ps | grep -v "grep" | grep -q "openvpn(${check_inst})"; then
exit 1
fi
fi
done
# Catch the result from the pipeline while-loop check safely
if [ "$?" -ne 0 ]; then
all_running="0"
fi
fi
# Recovery cascade: runs only if one or more instances failed to start
if [ "$all_running" = "0" ]; then
/etc/init.d/openvpn stop "$inst" >/dev/null 2>&1
sleep 1
@@ -147,15 +347,19 @@ ovpnstart() {
# OpenVPN self healing restart engine
ovpnrestart() {
shift # Remove "ovpnstart" from the arguments list
shift # Remove "ovpnrestart" from the arguments list
local inst="$1"
local sleepsec="$2"
# Execute optional validated sleep delay before doing any work
if validatesleep "$sleepsec"; then
sleep "$sleepsec"
fi
# If $inst contains only spaces or is empty, ensure it is completely empty
if [ -z "$(echo "$inst" | tr -d ' ')" ]; then
inst=""
fi
# Failsave restart cascade
/etc/init.d/openvpn stop "$inst" >/dev/null 2>&1
sleep 1
/etc/init.d/openvpn restart "$inst" >/dev/null 2>&1
@@ -167,26 +371,29 @@ ovpnrestart() {
ovpnstop() {
shift # Remove "ovpnstop" from the arguments list
local inst="$1"
local sleepsec="$2"
# Execute optional validated sleep delay before doing any work
if validatesleep "$sleepsec"; then
sleep "$sleepsec"
fi
# If $inst contains only spaces or is empty, ensure it is completely empty
if [ -z "$(echo "$inst" | tr -d ' ')" ]; then
inst=""
fi
# Double stop sequence with 1 second delay to clear locked procd pids safely
/etc/init.d/openvpn stop "$inst" >/dev/null 2>&1
sleep 1
/etc/init.d/openvpn stop "$inst" >/dev/null 2>&1
}
# openvpn service stop/start (PID-guarded with dynamic stop and restart/reload)
# openvpn service stop/start (PID-guarded with direct background workers)
ovpnservice() {
shift # Remove "ovpnservice" from the arguments list
local action_cmd="$1"
local inst="$2"
local pid_file="/var/run/luci-app-openvpn-plus-ovpn-service.pid"
# If $inst contains only spaces or is empty, ensure it is completely empty
if [ -z "$(echo "$inst" | tr -d ' ')" ]; then
inst=""
fi
@@ -196,19 +403,37 @@ ovpnservice() {
start-stop-daemon -K -q -p "$pid_file" 2>/dev/null
rm -f "$pid_file"
# 2. Start the self-healing sequence asynchronously in the background
# 2. Start the target command directly via the main script frame context (with sleep 3)
if [ "$action_cmd" = "start" ]; then
start-stop-daemon -S -b -m -p "$pid_file" -x /bin/sh -- -c "sleep 3; /usr/libexec/luci-app-openvpn-plus ovpnstart \"$inst\"; rm -f $pid_file"
start-stop-daemon -S -b -m -p "$pid_file" -x "$0" -- ovpnstart "$inst" 3
elif [ "$action_cmd" = "restart" ]; then
start-stop-daemon -S -b -m -p "$pid_file" -x /bin/sh -- -c "sleep 3; /usr/libexec/luci-app-openvpn-plus ovpnrestart \"$inst\"; rm -f $pid_file"
start-stop-daemon -S -b -m -p "$pid_file" -x "$0" -- ovpnrestart "$inst" 3
elif [ "$action_cmd" = "stop" ]; then
start-stop-daemon -S -b -m -p "$pid_file" -x /bin/sh -- -c "sleep 3; /usr/libexec/luci-app-openvpn-plus ovpnstop \"$inst\"; rm -f $pid_file"
start-stop-daemon -S -b -m -p "$pid_file" -x "$0" -- ovpnstop "$inst" 3
fi
fi
return 0
}
# firewall service stop/start (PID-guarded with automatic self-cleanup)
# firewall stop/start/restart engine
firewallexecute () {
shift # Remove "firewallexecute" from the arguments list
local action_cmd="$1"
local sleepsec="$2"
# 1. Execute optional validated sleep delay before doing any work
if validatesleep "$sleepsec"; then
sleep "$sleepsec"
fi
# 2. Call the standard OpenWrt system firewall controller safely
if [ "$action_cmd" = "stop" ] || [ "$action_cmd" = "start" ] || [ "$action_cmd" = "restart" ]; then
/etc/init.d/firewall "$action_cmd" >/dev/null 2>&1
fi
return 0
}
# firewall service stop/start (PID-guarded with direct background workers)
firewallservice() {
shift # Remove "firewallservice" from the arguments list
local action_cmd="$1"
@@ -219,8 +444,8 @@ firewallservice() {
start-stop-daemon -K -q -p "$pid_file" 2>/dev/null
rm -f "$pid_file"
# 2. Start worker and append the self-delete command to the end of the execution chain
start-stop-daemon -S -b -m -p "$pid_file" -x /bin/sh -- -c "sleep 3; /etc/init.d/firewall $action_cmd >/dev/null 2>&1; rm -f $pid_file"
# 2. Start the worker directly via the main script frame context (with sleep 3)
start-stop-daemon -S -b -m -p "$pid_file" -x "$0" -- firewallexecute "$action_cmd" 3
fi
return 0
}
@@ -228,9 +453,12 @@ firewallservice() {
# Secure helper to read and change firewall rules from LuCI without restrictions
firewallnft() {
shift # Remove "firewallnft" from the arguments list
# 2>&1 redirects stderr to stdout so LuCI catches syntax errors cleanly.
/usr/sbin/nft "$@" 2>&1
return 0
local chain="$1"
# Check if the chain name is empty or contains bad characters (only letters, numbers, and underscores are allowed)
if [ -z "$chain" ] || ! echo "$chain" | grep -Eq '^[A-Za-z0-9_]+$'; then
return 1
fi
/usr/sbin/nft list chain inet fw4 "$chain" 2>&1
}
# Secure helper to calculate cryptographic hashes using openssl dgst
@@ -251,52 +479,62 @@ symlink() {
local lan_ip=""
local link_filename=""
# Check if instance number is a valid digit
# Check if instance number is a valid digit.
if [ -z "$ovpn_num" ] || ! echo "$ovpn_num" | grep -q '^[0-9]\+$'; then
echo "ERROR: Invalid instance number."
return 1
fi
# Replace spaces with underscores or use instance name as fallback
# Clean the display name. Only letters, numbers, hyphens, and underscores are allowed.
if [ -n "$raw_display_name" ]; then
link_filename=`echo "$raw_display_name" | tr ' ' '_'`
else
link_filename=$(echo "$raw_display_name" | tr -cd 'A-Za-z0-9_-')
fi
# Fallback if the cleaned name is empty.
if [ -z "$link_filename" ]; then
link_filename="instance${ovpn_num}"
fi
# Full path for the web root link
local public_symlink_path="/www/${link_filename}_client.ovpn"
case "$action" in
create)
# Check if the source profile exists on disk
# Check if the source profile exists on disk.
if [ ! -f "$export_static_path" ]; then
echo "ERROR: Profile file missing at $export_static_path"
return 1
fi
# Create the web link
ln -sf "$export_static_path" "$public_symlink_path"
# Create a random crypt-token (9 random bytes as hex).
local secret_token=$(dd if=/dev/urandom bs=9 count=1 2>/dev/null | hexdump -e '"%02x"')
# Verify link and find active local router IP
if [ -L "$public_symlink_path" ]; then
lan_ip=`uci -q get network.lan.ipaddr`
if [ -z "$lan_ip" ]; then
lan_ip=`ubus call network.interface.lan status 2>/dev/null | jsonfilter -e '@["ipv4-address"].address'`
fi
if [ -z "$lan_ip" ]; then
# Path to the temporary session folder.
local session_dir="/www/ovpn-tmp-${secret_token}-${link_filename}"
local token_protected_file="${session_dir}/${link_filename}_client.ovpn"
# Create the directory safely.
mkdir -p "$session_dir"
# SECURITY FIX: create token-protected copy for the webserver
cp -f "$export_static_path" "$token_protected_file" 2>/dev/null
chmod 644 "$token_protected_file"
# Verify that the file copy exists and is valid.
if [ -f "$token_protected_file" ]; then
lan_ip=$(lanip)
if [ -z "$lan_ip" ] || [ "$lan_ip" = "0.0.0.0" ]; then
lan_ip="localhost"
fi
echo "SUCCESS: Link created at http://${lan_ip}/${link_filename}_client.ovpn"
# Return SUCCESS and the clean download link with sub-folder
echo "SUCCESS: http://${lan_ip}/ovpn-tmp-${secret_token}-${link_filename}/${link_filename}_client.ovpn"
else
echo "ERROR: Failed to create web link."
echo "ERROR: Failed to create web export file."
return 1
fi
;;
delete)
# Remove the link from the web root
rm -f "$public_symlink_path"
echo "SUCCESS: Link deleted from web root."
# Safe clean up using wildcard on the directory name.
# This removes the folder, the temporary copy, and deletes the static file.
rm -rf /www/ovpn-tmp-*-"${link_filename}"
echo "SUCCESS: Link directory and static profile deleted."
;;
*)
echo "Usage: /usr/libexec/luci-app-openvpn-plus symlink [num] [create|delete] [display_name]"
@@ -861,7 +1099,7 @@ wgetddns() {
local attempt=1
local max_attempts=3
while [ $attempt -le $max_attempts ]; do
wget_output=$(wget -T 10 --no-check-certificate --user-agent="'Mozilla/5.0'" -qO- "$url" 2>&1)
wget_output=$(wget -T 10 --user-agent="'Mozilla/5.0'" -qO- "$url" 2>&1)
wget_status=$?
# ok - break
@@ -1148,7 +1386,7 @@ cleanup() {
done
# Step 4: Delete all remaining temporary symlink files from the system
rm -f /www/*.ovpn
rm -rf /www/ovpn-tmp-*
rm -f "$conf_dir"/instance*.ovpn
return 0
}
@@ -1259,15 +1497,24 @@ initkeys() {
local exit_code=0
local dummy_payload="MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzV1c4B9x9C3x"
local ca_default_crt="$key_dir/ca_default.crt"
local server_default_crt="$key_dir/server_default.crt"
local server_default_key="$key_dir/server_default.key"
local client_default_crt="$key_dir/client_default.crt"
local client_default_key="$key_dir/client_default.key"
local dh_default_pem="$key_dir/dh_default.pem"
local server_default_tls2_key="$key_dir/server_default.tls2.key"
local client_default_tls2_key="$key_dir/client_default.tls2.key"
# Step 1: Check if all default files exist on the disk (Including new client-cert nodes)
[ -f "$key_dir/ca_default.crt" ] || missing=1
[ -f "$key_dir/server_default.crt" ] || missing=1
[ -f "$key_dir/server_default.key" ] || missing=1
[ -f "$key_dir/client_default.crt" ] || missing=1
[ -f "$key_dir/client_default.key" ] || missing=1
[ -f "$key_dir/dh_default.pem" ] || missing=1
[ -f "$key_dir/server_default.tls2.key" ] || missing=1
[ -f "$key_dir/client_default.tls2.key" ] || missing=1
[ -f "$ca_default_crt" ] || missing=1
[ -f "$server_default_crt" ] || missing=1
[ -f "$server_default_key" ] || missing=1
[ -f "$client_default_crt" ] || missing=1
[ -f "$client_default_key" ] || missing=1
[ -f "$dh_default_pem" ] || missing=1
[ -f "$server_default_tls2_key" ] || missing=1
[ -f "$client_default_tls2_key" ] || missing=1
# If all files exist, delete the lock file and stop immediately
if [ "$missing" -eq 0 ]; then
@@ -1275,8 +1522,13 @@ initkeys() {
return 0
fi
if [ ! -d "$key_dir" ]; then
mkdir -p "$key_dir"
# SECURITY: Force the directory permissions strictly to 0700 (root only)
chmod 700 "$key_dir"
fi
# Step 2: Files are missing, create lock file and set clean traps
mkdir -p "$key_dir"
touch "$lock_file"
trap "rm -f $lock_file" EXIT INT TERM
@@ -1307,48 +1559,48 @@ initkeys() {
# 4a) Generate Certificate Authority (CA)
openssl req -new -x509 -nodes -days 36500 -newkey rsa:2048 \
-keyout "$key_dir/ca_default.crt" \
-keyout "$ca_default_crt" \
-subj "/CN=${router_name} (OpenVPN CA)" 2>/dev/null && \
openssl req -new -x509 -nodes -days 36500 -key "$key_dir/ca_default.crt" \
-subj "/CN=${router_name} (OpenVPN CA)" 2>/dev/null >> "$key_dir/ca_default.crt" && \
openssl req -new -x509 -nodes -days 36500 -key "$ca_default_crt" \
-subj "/CN=${router_name} (OpenVPN CA)" 2>/dev/null >> "$ca_default_crt" && \
\
# 4b) Generate Server Private Key and CSR
openssl req -new -nodes -newkey ec -pkeyopt ec_paramgen_curve:prime256v1 \
-keyout "$key_dir/server_default.key" \
-keyout "$server_default_key" \
-out "$key_dir/server_default.csr" \
-subj "/CN=${router_name} (OpenVPN Server)" 2>/dev/null && \
\
# 4c) Sign Server Certificate using stable RAM config file
openssl x509 -req -days 36500 \
-in "$key_dir/server_default.csr" \
-CA "$key_dir/ca_default.crt" \
-CAkey "$key_dir/ca_default.crt" \
-CA "$ca_default_crt" \
-CAkey "$ca_default_crt" \
-set_serial "$$" \
-extfile "$ext_server_tmp" \
-out "$key_dir/server_default.crt" 2>/dev/null && \
-out "$server_default_crt" 2>/dev/null && \
\
# 4d) Generate Client Private Key and CSR
openssl req -new -nodes -newkey ec -pkeyopt ec_paramgen_curve:prime256v1 \
-keyout "$key_dir/client_default.key" \
-keyout "$client_default_key" \
-out "$key_dir/client_default.csr" \
-subj "/CN=${router_name} (OpenVPN Client)" 2>/dev/null && \
\
# 4e) Sign Client Certificate using stable RAM config file
openssl x509 -req -days 36500 \
-in "$key_dir/client_default.csr" \
-CA "$key_dir/ca_default.crt" \
-CAkey "$key_dir/ca_default.crt" \
-CA "$ca_default_crt" \
-CAkey "$ca_default_crt" \
-set_serial "$(( $$ + 1 ))" \
-extfile "$ext_client_tmp" \
-out "$key_dir/client_default.crt" 2>/dev/null && \
-out "$client_default_crt" 2>/dev/null && \
\
# 4f) Generate DH Parameters and OpenVPN static server keys
openssl dhparam -dsaparam -out "$key_dir/dh_default.pem" 2048 2>/dev/null && \
openvpn --genkey tls-crypt-v2-server "$key_dir/server_default.tls2.key" 2>/dev/null && \
openssl dhparam -dsaparam -out "$dh_default_pem" 2048 2>/dev/null && \
openvpn --genkey tls-crypt-v2-server "$server_default_tls2_key" 2>/dev/null && \
\
# 4g) Derive OpenVPN static client keys
client_name=$(echo -n "$router_name (OpenVPN Client TLSv2)" | openssl enc -base64) && \
openvpn --tls-crypt-v2 "$key_dir/server_default.tls2.key" --genkey tls-crypt-v2-client "$key_dir/client_default.tls2.key" "$client_name"
openvpn --tls-crypt-v2 "$server_default_tls2_key" --genkey tls-crypt-v2-client "$client_default_tls2_key" "$client_name"
# Save the status code of the complete command chain
exit_code=$?
@@ -1361,19 +1613,21 @@ initkeys() {
missing=1
else
missing=0
# SECURITY: Enforce 0600 on all successfully generated key files
chmod 600 "$key_dir"/*_default.*
fi
fi
# Step 5: If generation failed, create dummy files so openvpn does not crash
if [ "$missing" -eq 1 ] ; then
[ -f "$key_dir/ca_default.crt" ] || printf -- "-----BEGIN CERTIFICATE-----\n%s\n-----END CERTIFICATE-----\n" "$dummy_payload" > "$key_dir/ca_default.crt"
[ -f "$key_dir/server_default.crt" ] || printf -- "-----BEGIN CERTIFICATE-----\n%s\n-----END CERTIFICATE-----\n" "$dummy_payload" > "$key_dir/server_default.crt"
[ -f "$key_dir/server_default.key" ] || printf -- "-----BEGIN PRIVATE KEY-----\n%s\n-----END PRIVATE KEY-----\n" "$dummy_payload" > "$key_dir/server_default.key"
[ -f "$key_dir/client_default.crt" ] || printf -- "-----BEGIN CERTIFICATE-----\n%s\n-----END CERTIFICATE-----\n" "$dummy_payload" > "$key_dir/client_default.crt"
[ -f "$key_dir/client_default.key" ] || printf -- "-----BEGIN PRIVATE KEY-----\n%s\n-----END PRIVATE KEY-----\n" "$dummy_payload" > "$key_dir/client_default.key"
[ -f "$key_dir/dh_default.pem" ] || printf -- "-----BEGIN DH PARAMETERS-----\n%s\n-----END DH PARAMETERS-----\n" "$dummy_payload" > "$key_dir/dh_default.pem"
[ -f "$key_dir/server_default.tls2.key" ] || printf -- "-----BEGIN OpenVPN tls-crypt-v2 server key-----\n%s\n-----END OpenVPN tls-crypt-v2 server key-----\n" "$dummy_payload" > "$key_dir/server_default.tls2.key"
[ -f "$key_dir/client_default.tls2.key" ] || printf -- "-----BEGIN OpenVPN tls-crypt-v2 client key-----\n%s\n-----END OpenVPN tls-crypt-v2 client key-----\n" "$dummy_payload" > "$key_dir/client_default.tls2.key"
[ -f "$ca_default_crt" ] || printf -- "-----BEGIN CERTIFICATE-----\n%s\n-----END CERTIFICATE-----\n" "$dummy_payload" > "$ca_default_crt"
[ -f "$server_default_crt" ] || printf -- "-----BEGIN CERTIFICATE-----\n%s\n-----END CERTIFICATE-----\n" "$dummy_payload" > "$server_default_crt"
[ -f "$server_default_key" ] || printf -- "-----BEGIN PRIVATE KEY-----\n%s\n-----END PRIVATE KEY-----\n" "$dummy_payload" > "$server_default_key"
[ -f "$client_default_crt" ] || printf -- "-----BEGIN CERTIFICATE-----\n%s\n-----END CERTIFICATE-----\n" "$dummy_payload" > "$client_default_crt"
[ -f "$client_default_key" ] || printf -- "-----BEGIN PRIVATE KEY-----\n%s\n-----END PRIVATE KEY-----\n" "$dummy_payload" > "$client_default_key"
[ -f "$dh_default_pem" ] || printf -- "-----BEGIN DH PARAMETERS-----\n%s\n-----END DH PARAMETERS-----\n" "$dummy_payload" > "$dh_default_pem"
[ -f "$server_default_tls2_key" ] || printf -- "-----BEGIN OpenVPN tls-crypt-v2 server key-----\n%s\n-----END OpenVPN tls-crypt-v2 server key-----\n" "$dummy_payload" > "$server_default_tls2_key"
[ -f "$client_default_tls2_key" ] || printf -- "-----BEGIN OpenVPN tls-crypt-v2 client key-----\n%s\n-----END OpenVPN tls-crypt-v2 client key-----\n" "$dummy_payload" > "$client_default_tls2_key"
fi
# Step 6: Delete the lock file and remove all system traps when finished
@@ -1393,6 +1647,7 @@ keygen_worker() {
local custom="$6"
local log_file="/tmp/openvpn.keygen.log"
local out_ca_file="/tmp/openvpn.keygen.ca.tmp"
local ec_param_tmp="/tmp/openvpn.keygen.ec.tmp"
local out_server_key_file="/tmp/openvpn.keygen.server-key.tmp"
local out_server_cert_file="/tmp/openvpn.keygen.server-cert.tmp"
local out_client_key_file="/tmp/openvpn.keygen.client-key.tmp"
@@ -1404,9 +1659,14 @@ keygen_worker() {
local ca_key_buffer=""
local ca_cert_buffer=""
local ca_engine=""
local ec_param_tmp=""
rm -f "$log_file" && touch "$log_file" && chmod 666 "$log_file"
if [ ! -d "$key_dir" ]; then
mkdir -p "$key_dir"
# SECURITY: Force the directory permissions strictly to 0700 (root only)
chmod 700 "$key_dir"
fi
rm -f "$log_file" && touch "$log_file" && chmod 600 "$log_file"
case "$type" in
"ca")
active_out="$out_ca_file"
@@ -1415,10 +1675,10 @@ keygen_worker() {
ca_cert_buffer="$out_server_cert_file"
ca_engine="-newkey rsa:$bits"
if [ "$bits" = "ec" ]; then
ec_param_tmp="/tmp/openvpn.keygen.dh.tmp"
rm -f "$ec_param_tmp"
echo "[CMD] openssl ecparam -name prime256v1 -out $ec_param_tmp" >> "$log_file"
openssl ecparam -name prime256v1 -out "$ec_param_tmp" 2>> "$log_file"
chmod 600 "$ec_param_tmp"
ca_engine="-newkey ec:$ec_param_tmp"
fi
local target_cn="OpenVPN-CA-$instance"
@@ -1430,7 +1690,7 @@ keygen_worker() {
openssl req -new -x509 -nodes -days "$days" $ca_engine -subj "/CN=$target_cn" -keyout "$ca_key_buffer" -out "$ca_cert_buffer" $custom >/dev/null 2>> "$log_file"
if [ -f "$ca_key_buffer" ] && [ -s "$ca_key_buffer" ] && [ -f "$ca_cert_buffer" ] && [ -s "$ca_cert_buffer" ]; then
cat "$ca_cert_buffer" >> "$ca_key_buffer"
chmod 644 "$active_out"
chmod 600 "$active_out"
echo "LOG: WORKFLOW_SUCCESSFUL" >> "$log_file"
else
echo "ERROR: Cryptographic CA asset generation returned structural failure." >> "$log_file"
@@ -1454,7 +1714,7 @@ keygen_worker() {
openssl genrsa -out "$active_out" $custom "$bits" 2>> "$log_file"
fi
if [ -f "$active_out" ] && [ -s "$active_out" ]; then
chmod 644 "$active_out"
chmod 600 "$active_out"
echo "LOG: WORKFLOW_SUCCESSFUL" >> "$log_file"
else
echo "ERROR: Server private key buffer generation returned structural failure." >> "$log_file"
@@ -1492,7 +1752,7 @@ keygen_worker() {
rm -f "$ext_tmp"
if [ -f "$active_out" ] && [ -s "$active_out" ]; then
chmod 644 "$active_out"
chmod 600 "$active_out"
echo "LOG: WORKFLOW_SUCCESSFUL" >> "$log_file"
else
echo "ERROR: Server certificate dynamic signing pipeline returned structural failure." >> "$log_file"
@@ -1517,7 +1777,7 @@ keygen_worker() {
openssl genrsa -out "$active_out" $custom "$bits" 2>> "$log_file"
fi
if [ -f "$active_out" ] && [ -s "$active_out" ]; then
chmod 644 "$active_out"
chmod 600 "$active_out"
echo "LOG: WORKFLOW_SUCCESSFUL" >> "$log_file"
else
echo "ERROR: Client private key buffer generation returned structural failure." >> "$log_file"
@@ -1557,7 +1817,7 @@ keygen_worker() {
rm -f "$ext_tmp"
if [ -f "$active_out" ] && [ -s "$active_out" ]; then
chmod 644 "$active_out"
chmod 600 "$active_out"
echo "LOG: WORKFLOW_SUCCESSFUL" >> "$log_file"
else
echo "ERROR: Client certificate dynamic signing pipeline returned structural failure." >> "$log_file"
@@ -1576,7 +1836,7 @@ keygen_worker() {
echo "[CMD] openssl dhparam -dsaparam $custom -out '$active_out' '$bits'" >> "$log_file"
openssl dhparam -dsaparam $custom -out "$active_out" "$bits" >> "$log_file" 2>&1
if [ -f "$active_out" ] && [ -s "$active_out" ]; then
chmod 644 "$active_out"
chmod 600 "$active_out"
echo "LOG: WORKFLOW_SUCCESSFUL" >> "$log_file"
else
echo "ERROR: Diffie-Hellman cryptographic prime generation returned structural failure." >> "$log_file"
@@ -1593,7 +1853,7 @@ keygen_worker() {
echo "[CMD] openvpn --genkey tls-crypt-v2-server '$active_out'" >> "$log_file"
openvpn --genkey tls-crypt-v2-server "$active_out" 2>> "$log_file"
if [ -f "$active_out" ] && [ -s "$active_out" ]; then
chmod 644 "$active_out"
chmod 600 "$active_out"
echo "LOG: WORKFLOW_SUCCESSFUL" >> "$log_file"
else
echo "ERROR: Asymmetric v2 master server key engine tokens returned structural failure." >> "$log_file"
@@ -1615,7 +1875,7 @@ keygen_worker() {
echo "[CMD] openvpn --tls-crypt-v2 '$server_tls2_key' --genkey tls-crypt-v2-client '$active_out' '$target_tls_name_base64'" >> "$log_file"
openvpn --tls-crypt-v2 "$server_tls2_key" --genkey tls-crypt-v2-client "$active_out" "$target_tls_name_base64" 2>> "$log_file"
if [ -f "$active_out" ] && [ -s "$active_out" ]; then
chmod 644 "$active_out"
chmod 600 "$active_out"
echo "LOG: WORKFLOW_SUCCESSFUL" >> "$log_file"
else
echo "ERROR: Asymmetric v2 client key derivation engine tokens returned structural failure." >> "$log_file"
@@ -1637,11 +1897,19 @@ case "$1" in
lanip) lanip "$@" ;;
getnetstat) getnetstat "$@" ;;
bestcrypto) bestcrypto ;;
securepath) securepath "$@" ;;
readfile) readfile "$@" ;;
writefile) writefile "$@" ;;
makedir) makedir "$@" ;;
removefile) removefile "$@" ;;
removedir) removedir "$@" ;;
statfile) statfile "$@" ;;
ovpnver) ovpnver ;;
ovpnstart) ovpnstart "$@" ;;
ovpnrestart) ovpnrestart "$@" ;;
ovpnstop) ovpnstop "$@" ;;
ovpnservice) ovpnservice "$@" ;;
firewallexecute) firewallexecute "$@" ;;
firewallservice) firewallservice "$@" ;;
firewallnft) firewallnft "$@" ;;
openssldgst) openssldgst "$@" ;;
@@ -1696,7 +1964,7 @@ case "$1" in
*)
echo "Error: Unknown command '$1'"
echo "Valid commands: getmac lanip getnetstat bestcrypto ovpnver ovpnstart ovpnrestart ovpnstop ovpnservice firewallservice firewallnft openssldgst symlink readstatus iroute cleanipdns checkip resolveip checkport checksroute checkddns publicip wgetddns ddnsservice ucisortovpn cleanup keymeta keygenclean initkeys keygen"
echo "Valid commands: getmac lanip getnetstat bestcrypto securepath readfile writefile makedir removefile removedir statfile ovpnver ovpnstart ovpnrestart ovpnstop ovpnservice firewallexecute firewallservice firewallnft openssldgst symlink readstatus iroute cleanipdns checkip resolveip checkport checksroute checkddns publicip wgetddns ddnsservice ucisortovpn cleanup keymeta keygenclean initkeys keygen"
exit 1
;;
esac