mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-11-15 04:53:00 +08:00
🌴 Sync 2026-10-12 12:02:15
This commit is contained in:
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
|
||||
|
||||
Reference in new issue
Block a user